var http = require('http');

function processPlace(req, res) {
    var matchStrings = req.url.match("^/places/([a-z,0-9]+)$");
    if (matchStrings == null) {
        serverGetAllEntities(req, res, storage.getEntitiesByType(Place));
        serverPut(req, res, function (parsedData) {
            storage.addPlace(parsedData.name);
        });
        return;
    }
    var placeId = matchStrings[1];
    if (placeId != null) {
        var place = storage.getEntity(placeId);
        if (place == null || !(place instanceof Place)) {
            res.writeHead(404);
            res.end();
        }
        serverGetOne(req, res, place);
        serverPost(req, res, place);
        serveDelete(req, res, placeId);
        return;
    }
    res.writeHead(400);
    res.end();
}

http.createServer(function (req, res) {
    //OWNER RESOURCE
    if ((req.url.match("^/owners(.*)$"))) {
        processOwner(req, res);
        return;
    }
    //PLACE RESOURCE
    if ((req.url.match("^/places(.*)$"))) {
        processPlace(req, res);
        return;
    }
    //CAR RESOURCE
    if ((req.url.match("^/cars(.*)$"))) {
        processCar(req, res);
        return;
    }
    //PALCE RESOURCE
    if ((req.url.match("^/plates(.*)$"))) {
        processPlate(req, res);
        return;
    }
    res.writeHead(400);
    res.end();
}).listen(8888);

function processPlate(req, res) {
    var matchStrings = req.url.match("^/plates/([a-z,0-9]+)$");
    if (matchStrings == null) {
        serverGetAllEntities(req, res, storage.getEntitiesByType(Plate));
        serverPut(req, res, function (parsedData) {
            storage.addPlate(parsedData.code);
        });
        return;
    }
    var plateId = matchStrings[1];
    if (plateId != null) {
        var plate = storage.getEntity(plateId);
        if (plate == null || !(plate instanceof Plate)) {
            res.writeHead(404);
            res.end();
        }
        serverGetOne(req, res, plate);
        serverPost(req, res, plate);
        serveDelete(req, res, plateId);
        return;
    }
    res.writeHead(400);
    res.end();
}

function processCar(req, res) {
    var matchStrings = req.url.match("^/cars/([a-z,0-9]+)$");
    if (matchStrings == null) {
        serverGetAllEntities(req, res, storage.getEntitiesByType(Car));
        serverPut(req, res, function (parsedData) {
            storage.addCar(parsedData.name, parsedData.plate);
        });
        return;
    }
    var carId = matchStrings[1];
    if (carId != null) {
        var car = storage.getEntity(carId);
        if (car == null || !(car instanceof Car)) {
            res.writeHead(404);
            res.end();
        }
        serverGetOne(req, res, car);
        serverPost(req, res, car);
        serveDelete(req, res, carId);
        return;
    }
    res.writeHead(400);
    res.end();
}


function serverGetAllEntities(req, res, funnction) {
    if (req.method == "GET") {
        res.writeHead(200, {'Content-Type': 'application/json'});
        res.write(JSON.stringify(funnction));
        res.end();
        return;
    }
}

function serverGetOne(req, res, object) {
    if (req.method == "GET") {
        res.writeHead(200, {'Content-Type': 'application/json'});
        res.write(JSON.stringify(object));
        res.end();
    }
}

function serverPut(req, res, funnction) {
    if (req.method == "PUT") {
        res.writeHead(200, {'Content-Type': 'application/json'});
        req.setEncoding('utf8');
        req.on('data', function (data) {
            var parsedData = JSON.parse(data);
            funnction(parsedData);
            res.end();
        });
    }
}

function serverPost(req, res, object) {
    if (req.method == "POST") {
        res.writeHead(200, {'Content-Type': 'application/json'});
        req.setEncoding('utf8');
        req.on('data', function (data) {
            var parsedData = JSON.parse(data);
            res.write(data);
            storage.updateEntity(object, parsedData);
            res.end();
        });
    }
}

function serveDelete(req, res, entityId) {
    if (req.method == "DELETE") {
        res.writeHead(200, {'Content-Type': 'application/json'});
        storage.removeEntity(entityId);
        res.end();
    }
}

function processOwner(req, res) {
    var matchStrings = req.url.match("^/owners/([a-z,0-9]+)$");
    if (matchStrings == null) {
        serverGetAllEntities(req, res, storage.getEntitiesByType(Owner));
        serverPut(req, res, function (parsedData) {
            storage.addOwner(parsedData.name, parsedData.place, parsedData.cars);
        });
        return;
    }
    var ownerId = matchStrings[1];

    if (ownerId != null) {
        var owner = storage.getEntity(ownerId);
        if (owner == null || !(owner instanceof Owner)) {
            res.writeHead(404);
            res.end();
        }
        serverGetOne(req, res, owner);
        serverPost(req, res, owner);
        serveDelete(req, res, ownerId);
        return;
    }
    res.writeHead(400);
    res.end();
}


/**********************MODEL AND STORAGE*************************************/

var globalIdGenerator = 0;

function Owner(name) {
    this.id = globalIdGenerator++;
    this.name = name;
    this.place = null;
    this.cars = new Array();
};

function Car(name) {
    this.id = globalIdGenerator++;
    this.name = name;
    this.plate = null;
};

function Plate(code) {
    this.id = globalIdGenerator++;
    this.code = code;
};

function Place(name) {
    this.id = globalIdGenerator++;
    this.name = name;
};

var ownerAl = new Owner("Al");
var placePraha = new Place("Praha");

var carBMW = new Car("BMW5");
var carQ7 = new Car("Q7");

ownerAl.cars.push(carBMW, carQ7);
ownerAl.place = placePraha;

var plate1 = new Plate("AA8");
var plate2 = new Plate("REWQ9");

carBMW.plate = plate1;
carQ7.plate = plate2;

var storage = {
    entities: [
        ownerAl, placePraha, carBMW, carQ7, plate1, plate2
    ],

    getEntity: function (id) {
        for (var i = 0; i < this.entities.length; i++) {
            if (this.entities[i].id == id) {
                return this.entities[i];
            }
        }
        return null;
    },

    removeEntity: function (id) {
        for (var i = 0; i < this.entities.length; i++) {
            var entity = this.entities[i];
            if (entity.id == id) {
                this.entities.splice(i, 1);
                delete entity;
                return;
            }
        }
    },

    getEntitiesByType: function (type) {
        result = new Array();
        for (var i = 0; i < this.entities.length; i++) {
            if (this.entities[i] instanceof type) {
                result.push(this.entities[i]);
            }
        }
        return result;
    },

    getCars: function () {
        return this.getEntitiesByType(Car);
    },

    getOwners: function () {
        return this.getEntitiesByType(Owner);
    },

    addPlace: function (name) {
        var place = new Place(name);
        return this.entities.push(place);
    },

    addOwner: function (name, placeRef, carsData) {
        var owner = new Owner(name);
        if (placeRef != null) {
            owner.place = placeRef.split("/")[1];
        }
        if (carsData != null) {
            var cars = new Array();
            for (var i = 0; i < carsData.length; i++) {
                cars.push(this.getEntity(carsData[i].split("/")[1]));
            }
            owner.cars = cars;
        }
        return this.entities.push(owner);
    },

    addCar: function (name, plateRef) {
        var car = new Car(name);
        if (plateRef != null) {
            car.plate = plateRef.split("/")[1];
        }
        return this.entities.push(car);
    },

    addPlate: function (code) {
        var plate = new Plate(code);
        return this.entities.push(plate);
    },

    updateEntity: function (entity, data) {
        if (entity instanceof Owner) {
            entity.name = data.name;
            var placeData = data.place;
            if (placeData == null) {
                entity.place = null;
            } else {
                entity.place = this.getEntity(placeData.split("/")[1]);
            }

            var carsData = data.cars;
            if (carsData != null) {
                var cars = new Array();
                for (var i = 0; i < carsData.length; i++) {
                    cars.push(this.getEntity(carsData[i].split("/")[1]));
                }
            }
            entity.cars = cars;
        }
        if (entity instanceof Place) {
            entity.name = data.name;
        }
        if (entity instanceof Plate) {
            entity.code = data.code;
        }
        if (entity instanceof Car) {
            entity.name = data.name;
            var plateData = data.plate;
            if (plateData == null) {
                entity.plate = null;
            } else {
                entity.plate = this.getEntity(plateData.split("/")[1]);
            }
        }
    }

}